﻿using System;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;

namespace Yb
{
    public class UpdateInfo
    {
        [JsonProperty("version")]
        public string Version { get; set; }

        [JsonProperty("downloadUrl")]
        public string DownloadUrl { get; set; }

        [JsonProperty("releaseNotes")]
        public string ReleaseNotes { get; set; }
    }

    public class AutoUpdater
    {
        private readonly string _updateInfoUrl;

        public AutoUpdater(string updateInfoUrl)
        {
            if (updateInfoUrl == null)
                throw new ArgumentNullException(nameof(updateInfoUrl));
            _updateInfoUrl = updateInfoUrl;
        }

        public async Task<YbMessage> CheckAndShowUpdateDialogAsync()
        {
            try
            {
                HttpClient httpClient = new HttpClient();
                httpClient.Timeout = TimeSpan.FromSeconds(10);
                string json = await httpClient.GetStringAsync(_updateInfoUrl);
                httpClient.Dispose();

                UpdateInfo remoteInfo = JsonConvert.DeserializeObject<UpdateInfo>(json);

                if (remoteInfo == null)
                {
                    return new YbMessage(-1, "无法获取更新信息");
                }

                Version currentVer = GetCurrentVersion();
                Version remoteVer = ParseVersion(remoteInfo.Version);

                if (remoteVer <= currentVer)
                {
                    return new YbMessage(0, "当前已是最新版本");
                }

                DynamicUpdateForm updateForm = new DynamicUpdateForm(remoteInfo, currentVer.ToString(), remoteVer.ToString());
                updateForm.ShowDialog();
                return new YbMessage(0, "已经执行更新程序");
            }
            catch (Exception ex)
            {
                return new YbMessage(-1, $"检查更新失败：{ex.Message}");
            }
        }

        private Version GetCurrentVersion()
        {
            return Assembly.GetExecutingAssembly().GetName().Version;
        }

        private Version ParseVersion(string versionStr)
        {
            try
            {
                string[] parts = versionStr.Split('.');

                if (parts.Length < 2)
                {
                    return new Version(0, 0);
                }

                int major = int.TryParse(parts[0], out int m) ? m : 0;
                int minor = int.TryParse(parts[1], out int n) ? n : 0;
                int build = 0;
                int revision = 0;

                if (parts.Length >= 3)
                {
                    build = int.TryParse(parts[2], out int b) ? b : 0;
                }

                if (parts.Length >= 4)
                {
                    revision = int.TryParse(parts[3], out int r) ? r : 0;
                }

                return new Version(major, minor, build, revision);
            }
            catch
            {
                return new Version(0, 0, 0, 0);
            }
        }
    }

    internal class DynamicUpdateForm : Form
    {
        private readonly UpdateInfo _updateInfo;
        private readonly string _currentVersion;
        private readonly string _newVersion;
        private string _tempFilePath;
        private CancellationTokenSource _cts;
        private Label _lblStatus;
        private ProgressBar _progressBar;
        private Label _lblSpeed;
        private TextBox _txtNotes;
        private Button _btnCancel;
        private FileStream _fileStream;
        private Stream _contentStream;
        private HttpClient _httpClient;
        private HttpResponseMessage _response;

        public DynamicUpdateForm(UpdateInfo updateInfo, string currentVersion, string newVersion)
        {
            _updateInfo = updateInfo;
            _currentVersion = currentVersion;
            _newVersion = newVersion;
            InitializeControls();
            StartUpdateProcess();
        }

        private void InitializeControls()
        {
            this.Text = "软件更新";
            this.Size = new System.Drawing.Size(500, 350);
            this.StartPosition = FormStartPosition.CenterScreen;
            this.FormBorderStyle = FormBorderStyle.FixedSingle;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Icon = YbPrintPlug.Properties.Resources.updateicon;
            _lblStatus = new Label
            {
                Location = new System.Drawing.Point(15, 10),
                Size = new System.Drawing.Size(460, 20),
                AutoSize = false,
                Text = "正在准备下载..."
            };
            this.Controls.Add(_lblStatus);

            _progressBar = new ProgressBar
            {
                Location = new System.Drawing.Point(15, 35),
                Size = new System.Drawing.Size(460, 25),
                Style = ProgressBarStyle.Continuous
            };
            this.Controls.Add(_progressBar);

            _lblSpeed = new Label
            {
                Location = new System.Drawing.Point(15, 65),
                Size = new System.Drawing.Size(460, 20),
                AutoSize = false,
                Text = ""
            };
            this.Controls.Add(_lblSpeed);

            Label lblCurrent = new Label
            {
                Location = new System.Drawing.Point(15, 95),
                Size = new System.Drawing.Size(200, 20),
                Text = "当前版本：" + _currentVersion
            };
            Label lblNew = new Label
            {
                Location = new System.Drawing.Point(15, 115),
                Size = new System.Drawing.Size(200, 20),
                Text = "最新版本：" + _newVersion
            };
            this.Controls.Add(lblCurrent);
            this.Controls.Add(lblNew);

            Label lblNotes = new Label
            {
                Location = new System.Drawing.Point(15, 145),
                Size = new System.Drawing.Size(100, 20),
                Text = "更新内容："
            };
            _txtNotes = new TextBox
            {
                Location = new System.Drawing.Point(15, 165),
                Size = new System.Drawing.Size(460, 90),
                Multiline = true,
                ReadOnly = true,
                ScrollBars = ScrollBars.Vertical,
                Text = _updateInfo.ReleaseNotes ?? "无更新说明。"
            };
            this.Controls.Add(lblNotes);
            this.Controls.Add(_txtNotes);

            _btnCancel = new Button
            {
                Location = new System.Drawing.Point(400, 270),
                Size = new System.Drawing.Size(75, 25),
                Text = "取消"
            };
            _btnCancel.Click += (s, e) => CancelOrClose();
            this.Controls.Add(_btnCancel);

            this.FormClosed += OnFormClosed;
        }

        private void OnFormClosed(object sender, FormClosedEventArgs e)
        {
            CleanupResources();
        }

        private void CleanupResources()
        {
            try
            {
                _cts?.Cancel();

                _fileStream?.Dispose();
                _contentStream?.Dispose();
                _response?.Dispose();
                _httpClient?.Dispose();
                _cts?.Dispose();

                if (!string.IsNullOrEmpty(_tempFilePath) && File.Exists(_tempFilePath))
                {
                    File.Delete(_tempFilePath);
                }
            }
            catch
            {
                // 忽略清理错误
            }
        }

        private async void StartUpdateProcess()
        {
            _cts = new CancellationTokenSource();
            string fileName = Path.GetFileName(_updateInfo.DownloadUrl);
            if (string.IsNullOrEmpty(fileName))
            {
                fileName = "update_installer.exe";
            }
            _tempFilePath = Path.Combine(Path.GetTempPath(), fileName);

            try
            {
                _httpClient = new HttpClient();
                _response = await _httpClient.GetAsync(
                    _updateInfo.DownloadUrl, HttpCompletionOption.ResponseHeadersRead, _cts.Token);
                _response.EnsureSuccessStatusCode();

                long totalBytes = _response.Content.Headers.ContentLength ?? -1L;
                _contentStream = await _response.Content.ReadAsStreamAsync();
                _fileStream = new FileStream(_tempFilePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true);

                byte[] buffer = new byte[8192];
                long totalRead = 0;
                Stopwatch sw = Stopwatch.StartNew();
                long lastBytesRead = 0;
                DateTime lastUpdateTime = DateTime.Now;

                int bytesRead;
                while ((bytesRead = await _contentStream.ReadAsync(buffer, 0, buffer.Length, _cts.Token)) > 0)
                {
                    await _fileStream.WriteAsync(buffer, 0, bytesRead, _cts.Token);
                    totalRead += bytesRead;

                    // 计算下载速度（每秒）
                    DateTime currentTime = DateTime.Now;
                    double elapsedSeconds = (currentTime - lastUpdateTime).TotalSeconds;

                    if (elapsedSeconds >= 0.5) // 每0.5秒更新一次显示
                    {
                        long bytesSinceLastUpdate = totalRead - lastBytesRead;
                        double speed = elapsedSeconds > 0 ? bytesSinceLastUpdate / elapsedSeconds : 0;

                        if (totalBytes > 0)
                        {
                            int percentage = (int)(totalRead * 100 / totalBytes);
                            if (percentage > 100) percentage = 100;

                            _progressBar.Value = percentage;
                            _lblStatus.Text = $"正在下载... {FormatBytes(totalRead)} / {FormatBytes(totalBytes)} ({percentage}%)";

                            long remainingBytes = totalBytes - totalRead;
                            double etaSeconds = speed > 0 ? remainingBytes / speed : 0;

                            // 正确格式化速度显示
                            string speedStr;
                            if (speed >= 1024 * 1024) // MB/s
                            {
                                speedStr = $"{(speed / (1024 * 1024)):F1} MB/s";
                            }
                            else if (speed >= 1024) // KB/s
                            {
                                speedStr = $"{(speed / 1024):F1} KB/s";
                            }
                            else // B/s
                            {
                                speedStr = $"{speed:F0} B/s";
                            }

                            string etaStr = "";
                            if (etaSeconds > 0 && speed > 0)
                            {
                                TimeSpan eta = TimeSpan.FromSeconds(etaSeconds);
                                etaStr = eta.TotalHours >= 1 ?
                                    $"剩余约 {eta:h\\:mm\\:ss}" :
                                    $"剩余约 {eta:mm\\:ss}";
                            }

                            _lblSpeed.Text = $"速度: {speedStr} {etaStr}";
                        }
                        else
                        {
                            _lblStatus.Text = $"已下载: {FormatBytes(totalRead)}";

                            // 即使不知道总大小也显示速度
                            string speedStr;
                            if (speed >= 1024 * 1024)
                            {
                                speedStr = $"{(speed / (1024 * 1024)):F1} MB/s";
                            }
                            else if (speed >= 1024)
                            {
                                speedStr = $"{(speed / 1024):F1} KB/s";
                            }
                            else
                            {
                                speedStr = $"{speed:F0} B/s";
                            }
                            _lblSpeed.Text = $"速度: {speedStr}";
                        }

                        lastBytesRead = totalRead;
                        lastUpdateTime = currentTime;
                        Application.DoEvents();
                    }
                }

                await _fileStream.FlushAsync();
                _fileStream.Dispose();
                _fileStream = null;

                _contentStream.Dispose();
                _contentStream = null;

                _response.Dispose();
                _response = null;

                _httpClient.Dispose();
                _httpClient = null;

                _lblStatus.Text = "下载完成，正在启动安装程序...";
                _btnCancel.Text = "关闭";
                _btnCancel.Enabled = true;

                StartInstaller(_tempFilePath);
                Application.Exit();
            }
            catch (OperationCanceledException)
            {
                _lblStatus.Text = "更新已取消。";
                _btnCancel.Text = "关闭";
                _btnCancel.Enabled = true;
            }
            catch (Exception ex)
            {
                _lblStatus.Text = $"下载失败：{ex.Message}";
                _btnCancel.Text = "关闭";
                _btnCancel.Enabled = true;
            }
        }

        private void StartInstaller(string path)
        {
            try
            {
                string ext = Path.GetExtension(path).ToLowerInvariant();
                ProcessStartInfo psi = new ProcessStartInfo();
                psi.UseShellExecute = true;

                if (ext == ".msi")
                {
                    psi.FileName = "msiexec.exe";
                    psi.Arguments = "/i \"" + path + "\"";
                }
                else
                {
                    psi.FileName = path;
                }

                Process.Start(psi);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"启动安装程序失败：{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void CancelOrClose()
        {
            if (_btnCancel.Text == "关闭")
            {
                this.Close();
            }
            else
            {
                if (_cts != null && !_cts.IsCancellationRequested)
                {
                    _cts.Cancel();
                    _lblStatus.Text = "正在取消...";
                    _btnCancel.Enabled = false;

                    // 异步清理资源
                    Task.Run(() => CleanupResources());
                }
            }
        }

        private string FormatBytes(long bytes)
        {
            if (bytes < 1024)
                return bytes + " B";
            if (bytes < 1024 * 1024)
                return (bytes / 1024.0).ToString("F1") + " KB";
            if (bytes < 1024 * 1024 * 1024)
                return (bytes / (1024.0 * 1024)).ToString("F1") + " MB";
            return (bytes / (1024.0 * 1024 * 1024)).ToString("F1") + " GB";
        }
    }
}